package com.clstu.qqserver.service;

import com.clstu.qqcommon.Message;
import com.clstu.qqcommon.MessageType;
import com.clstu.qqcommon.User;
import com.mysql.jdbc.Driver;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Properties;

/**
 * 这是一个服务端程序,用于检测用户登录和创建与用户连接的线程
 */

public class QQServer {

    private ServerSocket serverSocket = null;
    private static final HashMap<String,User> validUsers =new HashMap<>();//模拟数据库,有效用户集合

    static {//初始化有效用户
        validUsers.put("100",new User("100","123456"));
        validUsers.put("200",new User("200","123456"));
        validUsers.put("300",new User("300","123456"));
        validUsers.put("至尊宝",new User("100","123456"));
        validUsers.put("紫霞仙子",new User("100","123456"));
        validUsers.put("菩提老祖",new User("100","123456"));
    }

    public static HashMap<String, User> getValidUsers() {
        return validUsers;
    }

    public static HashMap<String, User> getValidUsersFromDb() throws SQLException {
        HashMap<String,User> validUsers = new HashMap<>();
        Driver driver = new Driver();

        //2.得到连接
        String url = "jdbc:mysql://localhost:3306/cl_db01";
        Properties properties = new Properties();
        properties.setProperty("user","root");
        properties.setProperty("password","root");
        Connection connect = driver.connect(url, properties);//得到网络连接,类似数据通路

        //3.执行sql
        String sql = "select id, pwd from user";
        Statement statement = connect.createStatement();//用于执行sql语句并返回生成的结果对象
        ResultSet resultSet = statement.executeQuery(sql);//返回单个的结果集和
        //使用while循环来从resultSet中拿到数据
        while (resultSet.next()){//如果存在
            validUsers.put(resultSet.getString(1),new User(resultSet.getString(1),resultSet.getString(2)));
        }
        //4.关闭连接,释放资源
        statement.close();
        connect.close();
        return validUsers;
    }

    private boolean checkUser(String ID, String pwd){//该方法检测用户是否合法
        User user = validUsers.get(ID);
        if(user == null) return  false;//不在可登录列表中
        if(!user.getPwd().equals(pwd)) return false;//密码错误
        return true;
    }

    private boolean checkUserForDb(String ID, String pwd) throws SQLException {
        //1.注册驱动
        Driver driver = new Driver();

        //2.得到连接
        String url = "jdbc:mysql://localhost:3306/cl_db01";
        Properties properties = new Properties();
        properties.setProperty("user","root");
        properties.setProperty("password","root");
        Connection connect = driver.connect(url, properties);//得到网络连接,类似数据通路

        //3.执行sql
        String id = "'"+ID+"'";
        String sql = "select id, pwd from user where id = "+id;
        Statement statement = connect.createStatement();//用于执行sql语句并返回生成的结果对象

        ResultSet resultSet = statement.executeQuery(sql);//返回单个的结果集和

        if(resultSet.next()){//如果存在
            return resultSet.getString(2).equals(pwd);
        }
        //4.关闭连接,释放资源
        statement.close();
        connect.close();
        return false;//用户不存在就返回false
    }

    /** 该方法向数据库中插入一条数据,用于用新户注册是使用 */
    private boolean registeringToDb(User user) throws SQLException {
        //1.注册驱动
        Driver driver = new Driver();

        //2.得到连接
        String url = "jdbc:mysql://localhost:3306/cl_db01";
        Properties properties = new Properties();
        properties.setProperty("user","root");
        properties.setProperty("password","root");
        Connection connect = driver.connect(url, properties);//得到网络连接,类似数据通路

        //3.执行sql
        String id = user.getUserId();
        String pwd = user.getPwd();
        String sql = "insert into user values('"+id+ "', '"+pwd+"')";
        Statement statement = connect.createStatement();//用于执行sql语句并返回生成的结果对象
        int i = statement.executeUpdate(sql);//执行sql语句,返回受影响的行数
        //4.关闭连接,释放资源
        statement.close();
        connect.close();
        return i>0;
    }

    /** 该方法向数据库中插入一条数据,用于用新户注册是使用 */
    private boolean registering(User user) throws SQLException {
        validUsers.put(user.getUserId(), user);
        return true;
    }

    public QQServer(){
        try {
            serverSocket = new ServerSocket(9999);
            System.out.println("服务器端在9999端口监听");
            //启动推送消息线程
            new Thread(new SentNewsToAllClient()).start();

            //这是一个服务器,等待多个用户连接,所以一直监听,用死循环
            while (true){
                Socket socket = serverSocket.accept();//如果没有人连接会一直等(阻塞)

                //收取客户端传进来的User对象并对其进行登录验证
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message msg = (Message) ois.readObject();

                //得到socket对象的输出流
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

                if(msg.getMesType().equals(MessageType.MESSAGE_LOGIN)) {//如果是登录消息
                    //创建一个Message对象,用于回复登录(成功/失败)
                    Message message = new Message();
                    User user = msg.getUser();
                    if (checkUser(user.getUserId(), user.getPwd())) {//检测登录是否成功

                        //登录成功
                        System.out.println("服务端检测到用户" + user.getUserId() + "密码" + user.getPwd() + "连接服务器登陆成功!!!");
                        message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED);
                        oos.writeObject(message);//回复成功

                        //创建一个与客户端保持通信的线程
                        ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, user.getUserId());
                        serverConnectClientThread.start();//启动线程
                        //加入到管理类中便于管理
                        ServerConnectClientThreadManager.addServerConnectClientThread(user.getUserId(), serverConnectClientThread);

                    } else {

                        //登录失败
                        System.out.println("服务端检测到用户" + user.getUserId() + "密码" + user.getPwd() + "连接服务器登陆失败...");
                        message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);
                        oos.writeObject(message);//回复失败
                        socket.close();//登录失败就关闭这个客户的 socket连接
                    }
                }else if(msg.getMesType().equals(MessageType.MESSAGE_RESIST)){//如果是注册消息
                    User user = msg.getUser();
                    Message message = new Message();
                    System.out.println("服务端检测到用户" + user.getUserId() + "密码" + user.getPwd() + "新用户注册成功...!!");
                    validUsers.put(user.getUserId(),user);//保存用户的信息
                    registering(user);//将用户的信息写到数据库
                    message.setMesType(MessageType.MESSAGE_RESIST_SUCCEED);//回送成功的消息
                    oos.writeObject(message);
                    socket.close();
                }
            }

        } catch (IOException | ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                assert serverSocket != null;
                serverSocket.close();//最后服务器下线,关闭监听
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
